package com.itogis.interceptors.randomNumImage;

import java.awt.Color;
import java.awt.Font;
import java.awt.FontMetrics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.geom.AffineTransform;
import java.awt.image.BufferedImage;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.Random;

import javax.imageio.ImageIO;

public class VerifyImageGenerator {

	// 颜色数组，绘制字串时随机选择一个
	private static final Color[] CHAR_COLOR = { Color.RED, Color.BLUE,
			Color.GREEN, Color.MAGENTA };

	/**
	 * 生成验证码的字母表
	 */
	private static final char[] ALPHABET = { '1', '2', '3', '4', '5', '6', '7',
			'8', '9', 'A', 'a', 'b', 'C', 'c', 'd', 'E', 'e', 'F', 'f', 'G',
			'H', 'h', 'i', 'J', 'K', 'k', 'L', 'M', 'm', 'N', 'n', 'P', 'p',
			'Q', 'q', 'R', 'r', 'S', 's', 'T', 't', 'U', 'u', 'V', 'W', 'w',
			'X', 'x', 'Y', 'y' };

	private int fontSize = 30;
	private int charWidth = 20;
	private int charHeight = 42;

	// 随机数生成器
	private Random random = new Random();

	/**
	 * 生成图像的格式常量，JPEG格式,生成为文件时扩展名为.jpg； 输出到页面时需要设置MIME type 为image/jpeg
	 */
	public static String GRAPHIC_JPEG = "JPEG";
	/**
	 * 生成图像的格式常量，PNG格式,生成为文件时扩展名为.png； 输出到页面时需要设置MIME type 为image/png
	 */
	public static String GRAPHIC_PNG = "PNG";

	/**
	 * 生成随机验证码
	 * 
	 * @param length
	 *            验证码的长度
	 * @return 生成的随机验证码字符串
	 */
	public String generateVerifyCode(int length) {
		StringBuilder buf = new StringBuilder(length);
		for (int i = 0; i < length; i++) {
			buf.append(ALPHABET[this.randomInt(0, ALPHABET.length)]);
		}
		return buf.toString();
	}

	/**
	 * 根据验证码字符串生成图片
	 * 
	 * @param verifyCode
	 *            验证码字符串
	 * @param graphicFormat
	 *            设置生成的图像格式，值为GRAPHIC_JPEG或GRAPHIC_PNG
	 * @param out
	 *            图像结果输出流
	 * @throws IOException
	 */
	public void generateVerifyImage(String verifyCode, String graphicFormat,
			OutputStream out) throws IOException {
		// 计算图像的宽度和高度
		int w = (int) (charWidth * verifyCode.length() * 1.2f);// 冗余一个字符宽度
		int h = charHeight;

		// 创建内存图像区
		BufferedImage bufferedImage = new BufferedImage(w, h,
				BufferedImage.TYPE_INT_RGB);
		Graphics2D g2 = bufferedImage.createGraphics();
		// 开启抗锯齿
		g2.setRenderingHint(RenderingHints.KEY_ANTIALIASING,
				RenderingHints.VALUE_ANTIALIAS_ON);

		// 设置背景色
		Color backColor = Color.WHITE;
		g2.setBackground(backColor);
		g2.fillRect(0, 0, w, h);

		if (false) {
			// 随机产生155条干扰线，使图象中的认证码不易被其它程序探测到
			g2.setColor(getRandColor(160, 200));
			for (int i = 0; i < 155; i++) {
				int x = random.nextInt(w);
				int y = random.nextInt(h);
				int xl = random.nextInt(12);
				int yl = random.nextInt(12);
				g2.drawLine(x, y, x + xl, y + yl);
			}
		}

		// 设置基础字体
		Font baseFont = new Font(null, Font.PLAIN, fontSize);
		g2.setFont(baseFont);

		int xpos = 5;
		Color previousCharColor = null;
		for (int i = 0; i < verifyCode.length(); i++) {
			char ch = verifyCode.charAt(i);
			previousCharColor = this.getRandomCharColor(previousCharColor);
			Font font = baseFont.deriveFont(this.randomTransform());

			g2.setColor(previousCharColor);
			g2.setFont(font);

			FontMetrics fm = g2.getFontMetrics(font);
			int ypos = fm.getAscent() - fm.getLeading();
			g2.drawString(verifyCode.substring(i, i + 1), xpos, ypos);
			xpos += g2.getFontMetrics(font).charWidth(ch);
		}
		g2.dispose();
		int newW = xpos + charWidth;
		newW = Math.min(newW, w);
		bufferedImage.flush();
		// 截掉图片的右边的空白区域
		bufferedImage = bufferedImage.getSubimage(0, 0, newW, h);
		log("image width=" + bufferedImage.getWidth() + " height="
				+ bufferedImage.getHeight());
		// 输出到流
		ImageIO.write(bufferedImage, graphicFormat, out);
		out.flush();
	}

	/**
	 * 生成一个随机的坐标变换
	 * 
	 * @return
	 */
	protected AffineTransform randomTransform() {
		AffineTransform at = new AffineTransform();
		// rotate degree: 20 ~ 60;
		at.rotate(Math.PI / (this.randomInt(3, 9)));
		// scale y: 0.75 ~ 1.5
		at.scale(1, 0.75 + random.nextDouble() * 0.75);
		return at;
	}

	/**
	 * 返回[from,to)之间的一个随机整数
	 * 
	 * @param from
	 *            起始值
	 * @param to
	 *            结束值
	 * @return [from,to)之间的一个随机整数
	 */
	protected int randomInt(int from, int to) {
		if (from > to) {
			int tmp = from;
			from = to;
			to = tmp;
		}
		return from + random.nextInt(to - from);
	}

	private Color getRandomCharColor(Color previousColor) {
		Color color = CHAR_COLOR[randomInt(0, CHAR_COLOR.length)];
		if (color == previousColor) {
			return this.getRandomCharColor(previousColor);
		} else {
			return color;
		}
	}

	private Color getRandColor(int fc, int bc) {
		if (fc > 255) {
			fc = 255;
		}
		if (bc > 255) {
			bc = 255;
		}
		int r = fc + random.nextInt(bc - fc);
		int g = fc + random.nextInt(bc - fc);
		int b = fc + random.nextInt(bc - fc);
		return new Color(r, g, b);
	}

	private static final boolean LOG_ENABLED = false;

	private void log(Object message) {
		if (LOG_ENABLED) {
			System.out.println("RandomImage: " + message);
		}
	}

	/**
	 * @param args
	 * @throws Exception
	 */
	public static void main(String[] args) throws Exception {
		System.out.println("start");
		VerifyImageGenerator generator = new VerifyImageGenerator();
		String code = generator.generateVerifyCode(4);
		generator.generateVerifyImage(code, VerifyImageGenerator.GRAPHIC_PNG,
				new FileOutputStream("c:/myimg.png"));
		System.out.println("done: " + code);
	}

}
